package com.dev;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.text.Editable;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import com.fb.FileBrowserPage;
import com.log;
import java.util.ArrayList;
import android.view.inputmethod.TextAttribute;
public class IndentEditor extends BaseIndentEditor {//implements Thread.UncaughtExceptionHandler{
	static Paint selectionbgcolor=new Paint();
	volatile char[] text;
	volatile short[] textWS;
	volatile boolean handleOnShow=false;
	boolean autoIndentOnEnterKey=false;
	boolean horizontalScrollable;
    ArrayList<TabSpan> tabs=new ArrayList<TabSpan>();
	MyInputConnection mic=null;
    View bind;
	int baseline;
    int intEnum;
    Rect handleRegion1;
    Rect handleRegionSaved=null;
    Rect handleRegion2;
    Path handlePath1=new Path();
    Path handlePath2=new Path();
    boolean handle1fitEdge=false;
    boolean handle2fitEdge=false;
    static int handledl;
	static int handleHeight;
    final class TabSpan{
        int start;
        int end;
        int width;
        int tab;
        float fs[];
        String string;
        TabSpan next;
        TabSpan(int start){
            this.start=start;
        }
    }
    public IndentEditor(MainActivity ma){
		super(ma);
		selectionbgcolor.setColor(super.selectionbgcolor);
		setPadding((int)(6*ma.dp),8,0,0);
        setFocusable(true);
        setFocusableInTouchMode(true);
		textPaint.setTypeface(Typeface.MONOSPACE);
		letTextSize((int)ma.dp*ma.shr.getInt(GUISettings.NOTE_TEXT_SIZE,15));
		handledl=(int)(12*ma.dp);
		horizontalScrollable=!ma.shr.getBoolean("editorAutoWrapLine",false);
	}
    void atTextChanged(){
        if(ma.gui.tfNow instanceof FileBrowserTab){
            FileBrowserTab fbt=(FileBrowserTab)ma.gui.tfNow;
            FileBrowserPage fbp=fbt.fileBrowserPage;
            fbp.editorCanSave=true;
            ma.gui.removeViewAt(ma.gui.titleIndex);
            ma.gui.addView(ma.gui.titlebar,ma.gui.titleIndex,ma.gui.titlebarlp);
            ma.gui.ivSave.setColorFilter(null);
            ma.gui.ivSave.invalidate();
            ma.gui.ivRefresh.setColorFilter(null);
            ma.gui.ivRefresh.invalidate();
            
        }/*else if(ma.gui.tfNow instanceof HtmlBrowserTab){
            HtmlBrowserTab h=(HtmlBrowserTab)ie.ma.gui.tfNow;
            h.canSave=true;
            h.setTextColor(0xffff0000);
            ie.ma.gui.ivSave.setColorFilter(null);
            ie.ma.gui.ivSave.invalidate();
            ie.ma.gui.ivRefresh.setColorFilter(null);
            ie.ma.gui.ivRefresh.invalidate();
        }*/
        
    }
	@Override
	public void moveSelection(int a,int b){
		final int selectionStartWill=selectionStart+a;
		final int selectionEndWill=selectionEnd+b;
		int length=length();
		if(selectionStartWill>=0){
			if(selectionStartWill<=length){
				selectionStart=selectionStartWill;
			}else{
				selectionStart=length;
			}
		}else{
			selectionStart=0;
		}
		if(selectionEndWill>=0){
			if(selectionEndWill<=length){
				selectionEnd=selectionEndWill;
			}else{
				selectionEnd=length;
			}
		}else{
			selectionEnd=0;
		}
	}
	@Override
	public void letTextSize(int textSize){
		textPaint.setTextSize(textSize);
		lineHeight=textSize;
		baseline=(int)(lineHeight*0.88);
		tablen=(int)textPaint.measureText(tabWidth);
		if(text!=null){
			letText(text);
		}
	}
	public synchronized void letText(char[] text){
		if(text!=null){
			this.text=text;
			if(textWS==null||textWS.length<text.length)textWS=new short[text.length];
			tabs.clear();
            TabSpan ts=new TabSpan(0);
            tabs.add(ts);
            int len=text.length;
			for(int index=0;index<len;index++){
				char ch=text[index];
                if(ch=='\n'){
                    ts.end=index+1;
                    String sub=new String(text,ts.start,ts.end-ts.start);
                    ts.string=sub;
                    ts.width=(int)textPaint.measureText(sub);
                    ts=new TabSpan(index+1);
                    tabs.add(ts);
                }else{
                    textWS[index]=(short)textPaint.measureText(Character.toString(ch));
                    if(ch=='\t'){
                        ts.tab++;
                        int indexSaved=index;
                        for(index++;index<len;index++){
                            ch=text[index];
                            if(ch=='\t'){
                                ts.tab++;
                                textWS[index]=(short)textPaint.measureText(Character.toString(ch));
                            }else if(ch=='\n'){
                                ts.end=index;
                                String sub=new String(text,ts.start,indexSaved-ts.start);
                                ts.string=sub;
                                ts.width=(int)textPaint.measureText(sub);
                                TabSpan next=new TabSpan(index);
                                next.end=index+1;
                                next.string="\n";
                                ts.next=next;
                                ts=new TabSpan(index+1);
                                tabs.add(ts);
                                break;
                            }else{
                                ts.end=index;
                                String sub=new String(text,ts.start,indexSaved-ts.start);
                                ts.string=sub;
                                ts.width=(int)textPaint.measureText(sub);
                                TabSpan next=new TabSpan(index);
                                ts.next=next;
                                ts=next;
                                textWS[index]=(short)textPaint.measureText(Character.toString(ch));
                            }
                        }
                    }
                    
                }
			}
            ts.end=text.length;
            String sub=new String(text,ts.start,ts.end-ts.start);
            ts.string=sub;
            ts.width=(int)textPaint.measureText(sub);
		}else{
			log.alert("On void setText(char[])","parameter on null pointer");
		}
	}
	public void letHorizontalScrollable(boolean b){
		horizontalScrollable=b;
		scrollX=0;
		invalidate();
	}
	void replace(int a,int b,char[] s){
		repl(a,b,s);
        int len=length();
        if(selectionStart>len)selectionStart=len;
        if(selectionEnd>len)selectionStart=len;
	}
	char[] subText(int a,int b){
		if(a>b){
			int n=a;
			a=b;
			b=n;
		}else if(a==b){
			return new char[0];
		}
		for(int index=0,glyph=0;true;index++,glyph++){
			if(index<text.length){
				if(glyph==a){
					final int aa=index;
					for(;true;index++,glyph++){
						if(index<text.length){
							if(glyph==b){
								final int bb=index;
								char[] result=new char[bb-aa];
								for(int n=0;n<result.length;n++){
									result[n]=text[aa+n];
								}
								return result;
							}
							char ch=text[index];
							if(ch=='\\'){
								if(++index<text.length){
									ch=text[index];
									if(ch=='\\'){
										continue;
									}else if(ch=='p'){
										if(++index<text.length){
											ch=text[index];
											int w=ch>>>8;
											int h=ch&0x00ff;
											if((index+=w*h)<text.length){
												continue;
											}else{
												if(++glyph==b){
													final int bb=index;
													char[] result=new char[bb-aa];
													for(int n=0;n<result.length;n++){
														result[n]=text[aa+n];
													}
													return result;
												}else{
													log.alert("越界的参数b");
												}
												break;
											}
										}else{
											log.alert("异常的文本内容");
											break;
										}
									}else if(++glyph==b){
										final int bb=index;
										char[] result=new char[bb-aa];
										for(int n=0;n<result.length;n++){
											result[n]=text[aa+n];
										}
										return result;
									}else{
										continue;
									}
								}
							}
						}else if(glyph==b){
							final int bb=index;
							char[] result=new char[bb-aa];
							for(int n=aa,offs=0;n<bb&&offs<result.length;n++,offs++){
								result[offs]=text[n];
							}
							return result;
						}else{
							log.alert("char[] subText(final int a,final int b)","参数b越出上界");
							break;
						}
					}
					break;
				}
				char ch=text[index];
				if(ch=='\\'){
					if(++index<text.length){
						ch=text[index];
						if(ch=='\\'){
							continue;
						}else if(ch=='p'){
							if(++index<text.length){
								ch=text[index];
								int w=ch>>>8;
								int h=ch&0x00ff;
								if((index+=w*h)<text.length){
									continue;
								}else{
									if(++glyph==a){
										return new char[0];
									}
									break;
								}
							}else{
								log.alert("异常的文本内容");
								break;
							}
						}else{
							if(++glyph==a){
								final int aa=index;
								for(;true;index++,glyph++){
									if(index<text.length){
										if(glyph==b){
											final int bb=index;
											char[] result=new char[bb-aa];
											for(int n=0;n<result.length;n++){
												result[n]=text[aa+n];
											}
											return result;
										}
										ch=text[index];
										if(ch=='\\'){
											if(++index<text.length){
												ch=text[index];
												if(ch=='\\'){
													continue;
												}else if(ch=='p'){
													if(++index<text.length){
														ch=text[index];
														int w=ch>>>8;
														int h=ch&0x00ff;
														if((index+=w*h)<text.length){
															continue;
														}else{
															if(++glyph==b){
																final int bb=index;
																char[] result=new char[bb-aa];
																for(int n=0;n<result.length;n++){
																	result[n]=text[aa+n];
																}
																return result;
															}else{
																log.alert("越界的参数b");
															}
															break;
														}
													}else{
														log.alert("异常的文本内容");
														break;
													}
												}else if(++glyph==b){
													final int bb=index;
													char[] result=new char[bb-aa];
													for(int n=0;n<result.length;n++){
														result[n]=text[aa+n];
													}
													return result;
												}else{
													continue;
												}
											}
										}
									}else if(glyph==b){
										final int bb=index;
										char[] result=new char[bb-aa];
										for(int n=aa,offs=0;n<bb&&offs<result.length;n++,offs++){
											result[offs]=text[n];
										}
										return result;
									}else{
										log.alert("char[] subText(final int a,final int b)","参数b越出上界");
										break;
									}
								}
								break;
							}
						}
					}else if(++glyph==a){
						return new char[0];
					}
				}
			}else if(glyph==a){
				return new char[]{};
			}else{
				log.alert("char[] subText(final int a,final int b)","越出上界的参数a,"+"a="+a);
				break;
			}
		}
		return null;
	}
	public int length(){
		if(text==null)return 0;
		return text.length;
	}
	public void letSelection(int n){
		if(text==null){
			selectionStart=0;
			selectionEnd=0;
		}else{
			if(n>=0&&n<=text.length){
				selectionStart=n;
				selectionEnd=n;
			}else{
				log.alert("无效的参数","selection start:"+selectionStart+"\nselection end:"+selectionEnd);
			}
		}
	}
	public void letSelection(int a,int b){
		if(text==null){
			selectionStart=0;
			selectionEnd=0;
			return;
		}
		if(a<0){
			a=0;
			if(b<0){
				b=0;
			}else if(b>text.length){
				b=text.length;
			}
			selectionStart=a;
			selectionEnd=b;
		}else if(a>text.length){
			a=text.length;
			if(b<0){
				b=0;
			}else if(b>text.length){
				b=text.length;
			}
			selectionStart=a;
			selectionEnd=b;
		}else if(b<0){
			b=0;
			selectionStart=a;
			selectionEnd=b;
		}else if(b>text.length){
			b=text.length;
			selectionStart=a;
			selectionEnd=b;
		}else{
			selectionStart=a;
			selectionEnd=b;
		}
	}
	private void repl(int a,int b,char[] s){
		if(a>b){
			int n=a;
			a=b;
			b=n;
		}
		if(a<0||a>text.length||b<0||b>text.length){
			log.alert("无效的参数","selection start:"+selectionStart+"\nselection end:"+selectionEnd);
			return;
		}
		if(s!=null){
            //try{
			char[] textWill=new char[text.length+s.length-(b-a)];
            System.arraycopy(text,0,textWill,0,a);
            System.arraycopy(s,0,textWill,a,s.length);
            int org=a+s.length;
            System.arraycopy(text,b,textWill,org,text.length-b);
			letText(textWill);
            //}catch(Exception e){log.alert(e.toString());}
		}else{
			char[] textWill=new char[text.length-(b-a)];
            System.arraycopy(text,0,textWill,0,a);
			System.arraycopy(text,b,textWill,a,text.length-b);
			letText(textWill);
		}
		invalidate();
	}
	public int seeLineHeight(){
		return lineHeight;
	}
	void letLineHeight(int l){
		lineHeight=l;
	}
    int calculateClicked(int actionx,int actiony){
        if(horizontalScrollable){
            int row=(actiony-primey)/lineHeight;
            if(row<0)return -1;
            int size=tabs.size();
            if(row<size){
                int index=tabs.get(row).start;
                for(int a=0,x=primex,b;true;index++){
                    if(index<text.length){
                        char ch=text[index];
                        if(ch=='\n'){
                            return index;
                        }else if(ch=='\t'){
                            int xWill=((x-primex)/tablen+1)*tablen+primex;
                            b=x+(xWill-x)/2;
                            x=xWill;
                            if(actionx>=a&&actionx<b){
                                return index;
                            }
                            a=b;
                        }else{
                            int advance=textWS[index];
                            int xWill=x+advance;
                            b=x+advance/2;
                            x=xWill;
                            if(actionx>=a&&actionx<b){
                                return index;
                            }
                            a=b;
                        }
                    }else{
                        return text.length;
                    }
                }
            }else{
                return text.length;
            }
        }
        return -1;
	}

    @Override
    public void commitText(String s) {
        if(selectionStart==selectionEnd){
            if(s!=null){
                if(!s.isEmpty()){
                    int n=selectionStart;
                    repl(n,n,s.toCharArray());
                    letSelection(n+s.length());
                    atTextChanged();
                }
            }
        }else{
            atTextChanged();
            int a=Math.min(selectionStart,selectionEnd);
            int b=Math.max(selectionStart,selectionEnd);
            if(s==null){
                replace(a,b,null);
                selectionStart=a;
                selectionEnd=a;
            }else{
                replace(a,b,s.toCharArray());
                selectionStart=a;
                selectionEnd=a+s.length();
            }
        }
    }
    boolean onTextChanged_ignoreChange=false;
    @Override
    protected void onTextChanged(CharSequence text,int start,int lengthBefore,int lengthAfter){
        super.onTextChanged(text,start,lengthBefore,lengthAfter);
        //setText("");
        if(onTextChanged_ignoreChange){
            onTextChanged_ignoreChange=false;
            return;
        }
        //if(true)return;
        Editable ed=getEditableText();
        if(ed!=null){
            String s=getEditableText().toString();
            onTextChanged_ignoreChange=true;
            setText("");
            if(!s.isEmpty()){
                if(mic!=null){
                    commitText(s);//s.length());
                }
            }
        }
	}
    @Override
    protected void onLayout(boolean changed,int left,int top,int right,int bottom){
        super.onLayout(changed,left,top,right,bottom);
        primex=getPaddingLeft();
        primey=getPaddingTop();
        currentbgcolor=ma.shr.getInt("handwrittenbgcolor",defaultbgcolor);
	}
	Point touchDown=new Point();
	Point scrollSaved=new Point();
	Point scrollSaved_touchSaved=new Point();
	Point touchDown2=null;
	long touchDownTime;
	long recentTouchTime;
	Point recentTouch=new Point();
	volatile boolean fingerMoved=false;
	volatile boolean fingerPressed=false;
	boolean scaled;
	int fingerMovedOrientation;
	float fingerDistanceSaved;
	int textSizeSaved;
	WaitLongClick wlc;
	float speed;
	InertiaScroll inertiaScroll;
	int touchCtrl=0;
	AutoHideHandle ahh=null;
	@Override
	public boolean onTouchEvent(MotionEvent event){
		int ex=(int)event.getX();
		int ey=(int)event.getY();
		int rx=(int)event.getRawX();
		int ry=(int)event.getRawY();
		switch(event.getActionMasked()){
			case MotionEvent.ACTION_DOWN:
				scrollSaved.x=scrollX;
				scrollSaved.y=scrollY;
				scrollSaved_touchSaved.x=rx;
				scrollSaved_touchSaved.y=ry;
				scaled=false;
				touchDown.x=ex;
				touchDown.y=ey;
				fingerMoved=false;
				touchDownTime=System.currentTimeMillis();
				fingerPressed=true;
				if(wlc!=null)wlc.interrupt();
				if(inertiaScroll!=null)inertiaScroll.interrupt();
				wlc=new WaitLongClick();
				wlc.start();
				wlc.lastTouch.x=ex;
				wlc.lastTouch.y=ey;
				recentTouchTime=System.currentTimeMillis();
				recentTouch.x=ex;
				recentTouch.y=ey;
				touchCtrl=0;
				if(handleOnShow){
					int a=scrollX+ex;
					int b=scrollY+ey;
					if(selectionStart==selectionEnd){
						if(handleRegion1.contains(a,b)){
							handleRegionSaved=new Rect(handleRegion1);
							touchCtrl=1;
							if(ahh!=null){
								ahh.interrupt();
								ahh=null;
							}
						}
					}else{
						if(ahh!=null){
							ahh.interrupt();
						}
						handleOnShow=true;
						if(handleRegion1.contains(a,b)){
							handleRegionSaved=new Rect(handleRegion1);
							touchCtrl=2;
						}else if(handleRegion2.contains(a,b)){
							handleRegionSaved=new Rect(handleRegion2);
							touchCtrl=3;
						}
					}
				}
				//handle.setColor(0xff000000);
				break;
			case MotionEvent.ACTION_POINTER_DOWN:
				{
					wlc.waited=true;
					wlc.interrupt();
					textSizeSaved=(int)textPaint.getTextSize();
					int ex1=(int)event.getX(0);
					int ey1=(int)event.getY(0);
					int ex2=(int)event.getX(1);
					int ey2=(int)event.getY(1);
					int xdiff=Math.abs(ex1-ex2);
					int ydiff=Math.abs(ey1-ey2);
					float len=(int)Math.sqrt(xdiff*xdiff+ydiff*ydiff);
					fingerDistanceSaved=len;
				}
				break;
			case MotionEvent.ACTION_MOVE:
				if(event.getPointerCount()==1){
					if(fingerMoved){
						if(touchCtrl==1){
							int dx=ex-touchDown.x;
							int dy=ey-touchDown.y;
							handleRegion1.left=handleRegionSaved.left+dx;
							handleRegion1.top=handleRegionSaved.top+dy;
							handleRegion1.right=handleRegionSaved.right+dx;
							handleRegion1.bottom=handleRegionSaved.bottom+dy;
							int rr=-1;
							//rr=plainTextLayout.calculateClicked(handleRegion1.left+handledl,handleRegion1.top-lineHeight/10);
							if(rr>=0){
								letSelection(rr);
								showCursor=true;
								tcv.againWait=true;
								tcv.interrupt();
							}
							invalidate();
						}else if(touchCtrl==2){
							int dx=ex-touchDown.x;
							int dy=ey-touchDown.y;
							handleRegion1.left=handleRegionSaved.left+dx;
							handleRegion1.top=handleRegionSaved.top+dy;
							handleRegion1.right=handleRegionSaved.right+dx;
							handleRegion1.bottom=handleRegionSaved.bottom+dy;
							int rr;
							if(handle1fitEdge){
								int a=handleRegion1.left;
								int b=handleRegion1.top-lineHeight/10;
								rr=calculateClicked(a,b);
							}else{
								int a=handleRegion1.right;
								int b=handleRegion1.top-lineHeight/10;
								rr=calculateClicked(a,b);
							}
							if(rr>=0){
								letSelection(rr,selectionEnd);
								showCursor=true;
								tcv.againWait=true;
								tcv.interrupt();
							}
							invalidate();
						}else if(touchCtrl==3){
							int dx=ex-touchDown.x;
							int dy=ey-touchDown.y;
							handleRegion2.left=handleRegionSaved.left+dx;
							handleRegion2.top=handleRegionSaved.top+dy;
							handleRegion2.right=handleRegionSaved.right+dx;
							handleRegion2.bottom=handleRegionSaved.bottom+dy;
							int rr;
							if(handle2fitEdge){
								int a=handleRegion2.right;
								int b=handleRegion2.top-lineHeight/10;
								rr=calculateClicked(a,b);
							}else{
								int a=handleRegion2.left;
								int b=handleRegion2.top-lineHeight/10;
								rr=calculateClicked(a,b);
							}
							if(rr>=0){
								letSelection(selectionStart,rr);
								showCursor=true;
								tcv.againWait=true;
								tcv.interrupt();
							}
							invalidate();
						}else if(horizontalScrollable){
							if(fingerMovedOrientation==0){
								int scrollxWill=scrollSaved.x-(rx-scrollSaved_touchSaved.x);
								if(scrollxWill<=0){
									scrollSaved.x=0;
									scrollSaved_touchSaved.x=rx;
									scrollX=0;
									invalidate();
								}else if(scrollxWill>=scrollXMaximum){
									scrollSaved.x=scrollXMaximum;
									scrollSaved_touchSaved.x=rx;
									scrollX=scrollXMaximum;
									invalidate();
								}else{
									scrollX=scrollxWill;
									invalidate();
								}
								long dTime=System.currentTimeMillis()-recentTouchTime;
								if(dTime>0){
									float fingerMovedSpeed_will=(ex-recentTouch.x)/dTime;
									speed=(fingerMovedSpeed_will+speed)/2;
								}
							}else if(fingerMovedOrientation==1){
								int scrollyWill=scrollSaved.y-(ry-scrollSaved_touchSaved.y);
								//log.alert("scrolYMaximum:"+scrollYMaximum);
								if(scrollyWill<=0){
									scrollSaved.y=0;
									scrollSaved_touchSaved.y=ry;
									scrollY=0;
									invalidate();
								}else if(scrollyWill>=scrollYMaximum){
									scrollSaved.y=scrollYMaximum;
									scrollSaved_touchSaved.y=ry;
									scrollY=scrollYMaximum;
									invalidate();
								}else{
									scrollY=scrollyWill;
									invalidate();
								}
								long dTime=System.currentTimeMillis()-recentTouchTime;
								if(dTime>0){
									float fingerMovedSpeed_will=(ey-recentTouch.y)/dTime;
									speed=(fingerMovedSpeed_will+speed)/2;
								}
							}else{
								int scrollxWill=scrollSaved.x-(rx-scrollSaved_touchSaved.x);
								int scrollyWill=scrollSaved.y-(ry-scrollSaved_touchSaved.y);
								if(scrollxWill<=0){
									scrollSaved.x=0;
									scrollSaved_touchSaved.x=rx;
									if(scrollyWill<=0){
										scrollSaved.y=0;
										scrollSaved_touchSaved.y=ry;
										scrollX=0;
										scrollY=0;
										invalidate();
									}else if(scrollyWill>=scrollYMaximum){
										scrollSaved.y=scrollYMaximum;
										scrollSaved_touchSaved.y=ry;
										scrollX=0;
										scrollY=scrollYMaximum;
										invalidate();
									}else{
										scrollX=scrollxWill;
										scrollY=scrollyWill;
										invalidate();
									}
								}else if(scrollxWill>=scrollXMaximum){
									scrollSaved.x=scrollXMaximum;
									scrollSaved_touchSaved.x=rx;
									if(scrollyWill<=0){
										scrollSaved.y=0;
										scrollSaved_touchSaved.y=ry;
										scrollX=scrollXMaximum;
										scrollY=0;
										invalidate();
									}else if(scrollyWill>=scrollYMaximum){
										scrollSaved.y=scrollYMaximum;
										scrollSaved_touchSaved.y=ry;
										scrollX=scrollXMaximum;
										scrollY=scrollYMaximum;
										invalidate();
									}else{
										scrollX=scrollXMaximum;
										scrollY=scrollyWill;
										invalidate();
									}
								}else if(scrollyWill<=0){
									scrollSaved.y=0;
									scrollSaved_touchSaved.y=ry;
									scrollX=scrollxWill;
									scrollY=0;
									invalidate();
								}else if(scrollyWill>=scrollYMaximum){
									scrollSaved.y=scrollYMaximum;
									scrollSaved_touchSaved.y=ry;
									scrollX=scrollxWill;
									scrollY=scrollYMaximum;
									invalidate();
								}else{
									scrollX=scrollxWill;
									scrollY=scrollyWill;
									invalidate();
								}
							}	
						}else{
							int scrollyWill=scrollSaved.y-(ry-scrollSaved_touchSaved.y);
							if(scrollyWill<=0){
								scrollSaved.y=0;
								scrollSaved_touchSaved.y=ry;
								scrollX=0;
								scrollY=0;
								invalidate();
							}else if(scrollyWill<=scrollYMaximum){
								scrollX=0;
								scrollY=scrollyWill;
								invalidate();
							}else{
								scrollX=0;
								scrollY=scrollYMaximum;
								invalidate();
							}
							if(fingerMovedOrientation==1){
								long dTime=System.currentTimeMillis()-recentTouchTime;
								if(dTime>0){
									float fingerMovedSpeed_will=(ey-recentTouch.y)/dTime;
									speed=(fingerMovedSpeed_will+speed)/2;
								}
							}
						}
					}else{
						int dx=Math.abs(ex-touchDown.x);
						int dy=Math.abs(ey-touchDown.y);
						if(dx>10||dy>10){
							fingerMoved=true;wlc.interrupt();
							long dTime=System.currentTimeMillis()-recentTouchTime;
							if(dx>dy){
								fingerMovedOrientation=0;//水平移动
								if(dTime>0){
									speed=(ex-touchDown.x)/dTime;
								}
							}else if(dx<dy){//垂直移动
								//log.alert("ver");
								fingerMovedOrientation=1;
								if(dTime>0){
									speed=(ey-touchDown.y)/dTime;
								}
							}else{//方向不明
								fingerMovedOrientation=-1;
							}
						}
					}
					if(!wlc.waited){
						wlc.lastTouch.x=ex;
						wlc.lastTouch.y=ey;
					}
					recentTouchTime=System.currentTimeMillis();
					recentTouch.x=ex;
					recentTouch.y=ey;
				}else if(fingerDistanceSaved!=0){
					scaled=true;
					int ex1=(int)event.getX(0);
					int ey1=(int)event.getY(0);
					int ex2=(int)event.getX(1);
					int ey2=(int)event.getY(1);
					int xdiff=Math.abs(ex1-ex2);
					int ydiff=Math.abs(ey1-ey2);
					float len=(int)Math.sqrt(xdiff*xdiff+ydiff*ydiff);
					float scale=len/fingerDistanceSaved;
					int textSizeWill=(int)(textSizeSaved*scale);
					if(textSizeWill<=minTextSize){
						letTextSize(minTextSize);
					}else if(textSizeWill>maxTextSize){
						letTextSize(maxTextSize);
					}else{
						letTextSize(textSizeWill);
					}
					invalidate();
				}else{
					//log.alert("0");
				}
				break;
			case MotionEvent.ACTION_UP:
				//if(highlight==HighlightType.JAVA)log.alert("2333");
				fingerPressed=false;
				touchDown2=null;
				wlc.interrupt();
				if(fingerMoved){
					if(touchCtrl==1){
						touchCtrl=0;
						if(ahh!=null){
							ahh.interrupt();
							ahh=new AutoHideHandle();
							ahh.start();
						}else{
							ahh=new AutoHideHandle();
							ahh.start();
						}
						invalidate();
					}else if(touchCtrl==2||touchCtrl==3){
						touchCtrl=0;
						invalidate();
					}else{
						if(horizontalScrollable){
							inertiaScroll=new InertiaScroll();
							inertiaScroll.orientation=fingerMovedOrientation;
							inertiaScroll.initialSpeed=speed;
							inertiaScroll.initialScrollX=scrollX;
							inertiaScroll.initialScrollY=scrollY;
							inertiaScroll.start();
						}else if(fingerMovedOrientation==1){
							inertiaScroll=new InertiaScroll();
							inertiaScroll.orientation=fingerMovedOrientation;
							inertiaScroll.initialSpeed=speed;
							inertiaScroll.initialScrollX=scrollX;
							inertiaScroll.initialScrollY=scrollY;
							inertiaScroll.start();
						}
					}
				}else if(touchCtrl==0){
					if(wlc.waited){
					}else{
						ma.gui.removeViewAt(ma.gui.titleIndex);
                        ma.gui.addView(ma.gui.titlebar,ma.gui.titleIndex);
						if(ex>=0&&ex<getWidth()&&ey>=0&&ey<getHeight()){
							if(requestFocus()){
								if(canShowSoftInput)
									imm.showSoftInput(this,0);
								if(text!=null&&textWS!=null){
									int a=scrollX+ex;
									int b=scrollY+ey;
									int rr;
									rr=calculateClicked(a,b);
									if(rr>=0){
										letSelection(rr);
										showCursor=true;
										tcv.againWait=true;
										tcv.interrupt();
										handleOnShow=true;
										if(ahh==null){
											ahh=new AutoHideHandle();
											ahh.start();
										}else{
											ahh.interrupt();
											ahh=new AutoHideHandle();
											ahh.start();
										}
										invalidate();
									}
								}
							}
						}
					}
				}
				break;
			case MotionEvent.ACTION_CANCEL:
				touchDown2=null;
				fingerPressed=false;
				wlc.interrupt();
				if(touchCtrl==1){
					touchCtrl=0;
					invalidate();
				}else{
					if(fingerMoved){
					}else{
						if(ex>=0&&ex<=getWidth()&&ey>=0&&ey<=getHeight()){
							if(requestFocus()){
								if(canShowSoftInput)
									imm.showSoftInput(this,0);
							}
						}
					}
				}
		}
		return true;
	}
	void measureHandleStart(int x,int y){
		int handledl=this.handledl*5/3;
		if(touchCtrl==2){
			handlePath1.reset();
			if(!handle1fitEdge){
				//handle1fitEdge=false;
				handlePath1.moveTo(handleRegion1.right,handleRegion1.top);
				handlePath1.lineTo(handleRegion1.right,handleRegion1.bottom);
				handlePath1.lineTo(handleRegion1.left,handleRegion1.bottom);
				handlePath1.lineTo(handleRegion1.left,handleRegion1.top+handledl);
				handlePath1.close();
			}else{
				//handle1fitEdge=true;
				handlePath1.moveTo(handleRegion1.left,handleRegion1.top);
				handlePath1.lineTo(handleRegion1.right,handleRegion1.top+handledl);
				handlePath1.lineTo(handleRegion1.right,handleRegion1.bottom);
				handlePath1.lineTo(handleRegion1.left,handleRegion1.bottom);
				handlePath1.close();
			}
			return;
		}
		handleRegion1=new Rect();
		handlePath1.reset();
		if(x>=handleFitEdgeLim){
			handle1fitEdge=false;
			handleRegion1.left=x-handledl;
			handleRegion1.top=y+lineHeight;
			handleRegion1.right=x;
			handleRegion1.bottom=handleRegion1.top+handledl*2*3/2;
			handlePath1.moveTo(x,handleRegion1.top);
			handlePath1.lineTo(handleRegion1.right,handleRegion1.bottom);
			handlePath1.lineTo(handleRegion1.left,handleRegion1.bottom);
			handlePath1.lineTo(handleRegion1.left,handleRegion1.top+handledl);
		}else{
			handle1fitEdge=true;
			handleRegion1.left=x;
			handleRegion1.top=y+lineHeight;
			handleRegion1.right=x+handledl;
			handleRegion1.bottom=handleRegion1.top+handledl*2*3/2;
			handlePath1.moveTo(x,handleRegion1.top);
			handlePath1.lineTo(handleRegion1.right,handleRegion1.top+handledl);
			handlePath1.lineTo(handleRegion1.right,handleRegion1.bottom);
			handlePath1.lineTo(handleRegion1.left,handleRegion1.bottom);
		}
		handlePath1.close();
	}
	void measureHandleEnd(int x,int y){
		int handledl=this.handledl*5/3;
		if(touchCtrl==3){//handle end on dragging
			handlePath2.reset();
			if(!handle2fitEdge){
				x=handleRegion2.left;
				handlePath2.moveTo(x,handleRegion2.top);
				handlePath2.lineTo(handleRegion2.right,handleRegion2.top+handledl);
				handlePath2.lineTo(handleRegion2.right,handleRegion2.bottom);
				handlePath2.lineTo(handleRegion2.left,handleRegion2.bottom);
				handlePath2.close();
			}else{
				handlePath2.moveTo(handleRegion2.right,handleRegion2.top);
				handlePath2.lineTo(handleRegion2.right,handleRegion2.bottom);
				handlePath2.lineTo(handleRegion2.left,handleRegion2.bottom);
				handlePath2.lineTo(handleRegion2.left,handleRegion2.top+handledl);
				handlePath2.close();
			}
			return;
		}
		int le=x-scrollX;
		int vw=getWidth();
		int sx=scrollX;
		handleRegion2=new Rect();
		handlePath2.reset();
		if(vw-le<handleFitEdgeLim){//the cursor is very near viewport's edge
			handle2fitEdge=true;
			handleRegion2.left=x-handledl;
			handleRegion2.top=y+lineHeight;
			handleRegion2.right=x;
			handleRegion2.bottom=handleRegion2.top+handledl*2*3/2;
			//if(handleRegion2.left>vw+sx){//this handle is invisible
			//}else{
				handlePath2.moveTo(handleRegion2.right,handleRegion2.top);
				handlePath2.lineTo(handleRegion2.right,handleRegion2.bottom);
				handlePath2.lineTo(handleRegion2.left,handleRegion2.bottom);
				handlePath2.lineTo(handleRegion2.left,handleRegion2.top+handledl);
				handlePath2.close();
			//}
		}else{
			handle2fitEdge=false;
			handleRegion2.left=x;
			handleRegion2.top=y+lineHeight;
			handleRegion2.right=x+handledl;
			handleRegion2.bottom=handleRegion2.top+handledl*2*3/2;
			handlePath2.moveTo(x,handleRegion2.top);
			handlePath2.lineTo(handleRegion2.right,handleRegion2.top+handledl);
			handlePath2.lineTo(handleRegion2.right,handleRegion2.bottom);
			handlePath2.lineTo(handleRegion2.left,handleRegion2.bottom);
			handlePath2.close();
		}
	}
	void measureHandle(int x,int y){
		if(touchCtrl==1){
			x=handleRegion1.left+handledl;
			handlePath1.reset();
			handlePath1.moveTo(x,handleRegion1.top);
			handlePath1.lineTo(handleRegion1.right,handleRegion1.top+handledl);
			handlePath1.lineTo(handleRegion1.right,handleRegion1.bottom);
			handlePath1.lineTo(handleRegion1.left,handleRegion1.bottom);
			handlePath1.lineTo(handleRegion1.left,handleRegion1.top+handledl);
			handlePath1.close();
			handle.setStyle(Paint.Style.FILL);
			return;
		}
		if(selectionStart==selectionEnd){
			handleRegion1=new Rect();
			handleRegion1.left=x-handledl;
			handleRegion1.top=y+lineHeight;
			handleRegion1.right=x+handledl;
			handleRegion1.bottom=handleRegion1.top+handledl*2*3/2;
			handlePath1.reset();
			handlePath1.moveTo(x,handleRegion1.top);
			handlePath1.lineTo(handleRegion1.right,handleRegion1.top+handledl);
			handlePath1.lineTo(handleRegion1.right,handleRegion1.bottom);
			handlePath1.lineTo(handleRegion1.left,handleRegion1.bottom);
			handlePath1.lineTo(handleRegion1.left,handleRegion1.top+handledl);
			handlePath1.close();
			handle.setStyle(Paint.Style.FILL);
		}
	}
	int primex;
	int primey;
	@Override
	public void draw(Canvas canvas){
		canvas.drawColor(currentbgcolor);
		if(text!=null&&textWS!=null){
			Paint cursor=new Paint();
			int cursorWidth=Math.round(textPaint.getTextSize()/13);
			if(cursorWidth<=0)cursorWidth=1;
			cursor.setStrokeWidth(cursorWidth);
			int vw=getWidth();
			int vh=getHeight();
			int startx=primex;
			int starty=primey;
			canvas.translate(-scrollX,-scrollY);
			if(horizontalScrollable){
				int startLine=(scrollY-primey)/lineHeight;
				int size=tabs.size();
				if(startLine>=size)return;
                int index=tabs.get(startLine).start;
                starty=startLine*lineHeight+primey;
				scrollYMaximum=size*lineHeight+primey;
				scrollXMaximum=0;
				outmost:
				for(;true;index++){//此字符位于视口内
					if(index<text.length){
						for(int ii=index;true;ii++){
							if(ii<text.length){
								char ch=text[ii];
								if(ii>=selectionEnd){//画出余下行
									if(ii==selectionEnd){
										Paint p=new Paint();
										p.setStyle(Paint.Style.FILL);
										p.setColor(currentLineHighlight);
										canvas.drawRect(scrollX,starty,vw+scrollX,starty+lineHeight,p);
									}
									for(;true;index++){
										if(index==selectionStart){//画光标
											if(index==selectionEnd){
												measureHandle(startx,starty);
												if(showCursor){
													canvas.drawLine(startx,starty,startx,starty+lineHeight,cursor);
												}
											}else{
												measureHandleStart(startx,starty);
											}
										}else if(index==selectionEnd){
											if(selectionStart!=selectionEnd){
												measureHandleEnd(startx,starty);
											}
										}
										int scrollYMaximum_will=starty+lineHeight;
										scrollYMaximum=scrollYMaximum_will>scrollYMaximum?scrollYMaximum_will:scrollYMaximum;
										if(starty-scrollY>vh){
											break outmost;
										}
										if(index<text.length){
											ch=text[index];
											int startxWill=0;
											if(ch=='\n'){
												int startyWill=starty+lineHeight;
												startxWill=primex;
												if(index>=selectionStart&&index<selectionEnd){//换行符是被选中的，画出它的背景高亮
													canvas.drawRect(startx,starty,vw+scrollX,starty+lineHeight,selectionbgcolor);
												}else if(index>=selectionEnd&&index<selectionStart){
													canvas.drawRect(startx,starty,vw+scrollX,starty+lineHeight,selectionbgcolor);
												}
												startx=startxWill;
												starty=startyWill;
											}else if(ch=='\t'){
												startxWill=((startx-primex)/tablen+1)*tablen+primex;
												if(index>=selectionStart&&index<selectionEnd){//画选中高亮
													canvas.drawRect(startx,starty,startxWill,starty+lineHeight,selectionbgcolor);
												}else if(index>=selectionEnd&&index<selectionStart){
													canvas.drawRect(startx,starty,startxWill,starty+lineHeight,selectionbgcolor);
												}
												startx=startxWill;
											}else{
												startxWill=startx+textWS[index];
												canvas.drawText(Character.toString(ch),startx,starty+baseline,textPaint);
												if(index>=selectionStart&&index<selectionEnd){//画选中高亮
													canvas.drawRect(startx,starty,startxWill,starty+lineHeight,selectionbgcolor);
												}else if(index>=selectionEnd&&index<selectionStart){
													canvas.drawRect(startx,starty,startxWill,starty+lineHeight,selectionbgcolor);
												}
												startx=startxWill;
											}
											if(scrollXMaximum<startxWill){
												scrollXMaximum=startxWill;
											}
										}else{
											break;
										}
									}
									break outmost;
								}else if(ch=='\n'){
									break;
								}
							}else{
								Paint p=new Paint();
								p.setStyle(Paint.Style.FILL);
								p.setColor(currentLineHighlight);
								canvas.drawRect(scrollX,starty,vw+scrollX,starty+lineHeight,p);
								break;
							}
						}
						for(;true;index++){//画出一行纯文本
							if(index==selectionStart){//画光标
								if(index==selectionEnd){
									measureHandle(startx,starty);
									if(showCursor){
										canvas.drawLine(startx,starty,startx,starty+lineHeight,cursor);
									}
								}else{
									measureHandleStart(startx,starty);
								}
							}else if(index==selectionEnd){
								if(selectionStart!=selectionEnd){
									measureHandleEnd(startx,starty);
								}
							}
							int scrollYMaximum_will=starty+lineHeight;
							scrollYMaximum=scrollYMaximum_will>scrollYMaximum?scrollYMaximum_will:scrollYMaximum;
							if(starty-scrollY>vh){
								break outmost;
							}
							if(index<text.length){
								char ch=text[index];
								int startxWill=0;
								if(ch=='\n'){
									int startyWill=starty+lineHeight;
									startxWill=primex;
									if(index>=selectionStart&&index<selectionEnd){//换行符是被选中的，画出它的背景高亮
										canvas.drawRect(startx,starty,vw+scrollX,starty+lineHeight,selectionbgcolor);
									}else if(index>=selectionEnd&&index<selectionStart){
										canvas.drawRect(startx,starty,vw+scrollX,starty+lineHeight,selectionbgcolor);
									}
									startx=startxWill;
									starty=startyWill;
									break;
								}else if(ch=='\t'){
									startxWill=((startx-primex)/tablen+1)*tablen+primex;
									if(index>=selectionStart&&index<selectionEnd){//画选中高亮
										canvas.drawRect(startx,starty,startxWill,starty+lineHeight,selectionbgcolor);
									}else if(index>=selectionEnd&&index<selectionStart){
										canvas.drawRect(startx,starty,startxWill,starty+lineHeight,selectionbgcolor);
									}
									startx=startxWill;
								}else{
									startxWill=startx+textWS[index];
									if(index>=selectionStart&&index<selectionEnd){//画选中高亮
										canvas.drawRect(startx,starty,startxWill,starty+lineHeight,selectionbgcolor);
									}else if(index>=selectionEnd&&index<selectionStart){
										canvas.drawRect(startx,starty,startxWill,starty+lineHeight,selectionbgcolor);
									}
									canvas.drawText(Character.toString(ch),startx,starty+baseline,textPaint);
									startx=startxWill;
								}
								if(scrollXMaximum<startxWill){
									scrollXMaximum=startxWill;
								}
							}else{
								break outmost;
							}
						}
					}else{
						Paint p=new Paint();
						p.setStyle(Paint.Style.FILL);
						p.setColor(currentLineHighlight);
						canvas.drawRect(scrollX,starty,vw+scrollX,starty+lineHeight,p);
						if(index==selectionStart){//画光标
							if(index==selectionEnd){
								measureHandle(startx,starty);
								if(showCursor){
									canvas.drawLine(startx,starty,startx,starty+lineHeight,cursor);
								}
							}else{
								measureHandleStart(startx,starty);
							}
						}else if(index==selectionEnd){
							if(selectionStart!=selectionEnd){
								measureHandleEnd(startx,starty);
							}
						}
						break;
					}
				}//outmost loop
			}else{//自动折行的纯文本
				int startyMin=scrollY-lineHeight;
				outmost:
				for(int index=0;true;index++){
					if(index<text.length){
						if(starty<startyMin){
							char ch=text[index];
							if(ch=='\n'){
								starty+=lineHeight;
								startx=primex;
							}else if(ch=='\t'){
								int startxWill=((startx-primex)/tablen+1)*tablen+primex;
								if(startxWill<vw){
									startx=startxWill;
								}else{
									starty+=lineHeight;
									startx=primex;
									index--;
								}
							}else{
								int adv=textWS[index];
								int startxWill=startx+adv;
								if(startxWill<vw){
									startx=startxWill;
								}else{
									startx=primex;
									starty+=lineHeight;
									index--;
								}
							}
						}else{
							outloop://画折行的纯文本
							for(;true;index++){
								if(index<text.length){
									for(int ii=index,xx=primex;true;ii++){
										if(ii<text.length){
											char ch=text[ii];
											if(ii>=selectionEnd){
												if(ii==selectionEnd){
													Paint p=new Paint();
													p.setStyle(Paint.Style.FILL);
													p.setColor(currentLineHighlight);
													canvas.drawRect(scrollX,starty,vw+scrollX,starty+lineHeight,p);
												}
												for(;true;index++){//画出余下行
													if(index==selectionStart){//画光标
														if(index==selectionEnd){
															measureHandle(startx,starty);
															if(showCursor){
																canvas.drawLine(startx,starty,startx,starty+lineHeight,cursor);
															}
														}else{
															measureHandleStart(startx,starty);
														}
													}else if(index==selectionEnd){
														if(selectionStart!=selectionEnd){
															measureHandleEnd(startx,starty);
														}
													}
													int scrollYMaximum_will=starty+lineHeight;
													scrollYMaximum=scrollYMaximum_will>scrollYMaximum?scrollYMaximum_will:scrollYMaximum;
													if(starty-scrollY>vh){
														break outloop;
													}
													if(index<text.length){
														ch=text[index];
														if(ch=='\t'){
															int startxWill=((startx-primex)/tablen+1)*tablen+primex;
															if(index>=selectionStart&&index<selectionEnd){//画选中高亮
																canvas.drawRect(startx,starty,startxWill,starty+lineHeight,selectionbgcolor);
															}else if(index>=selectionEnd&&index<selectionStart){
																canvas.drawRect(startx,starty,startxWill,starty+lineHeight,selectionbgcolor);
															}
															if(startxWill<vw){
																startx=startxWill;
															}else{
																starty+=lineHeight;
																startx=primex;
															}
														}else if(ch=='\n'){
															int startyWill=starty+lineHeight;
															int startxWill=primex;
															if(index>=selectionStart&&index<selectionEnd){//换行符是被选中的，画出它的背景高亮
																canvas.drawRect(startx,starty,vw+scrollX,starty+lineHeight,selectionbgcolor);
															}else if(index>=selectionEnd&&index<selectionStart){
																canvas.drawRect(startx,starty,vw+scrollX,starty+lineHeight,selectionbgcolor);
															}
															startx=startxWill;
															starty=startyWill;
														}else{
															int advance=textWS[index];
															int startxWill=startx+advance;
															if(startxWill<vw){
																if(index>=selectionStart&&index<selectionEnd){//画选中高亮
																	canvas.drawRect(startx,starty,startxWill,starty+lineHeight,selectionbgcolor);
																}else if(index>=selectionEnd&&index<selectionStart){
																	canvas.drawRect(startx,starty,startxWill,starty+lineHeight,selectionbgcolor);
																}
																canvas.drawText(Character.toString(ch),startx,starty+baseline,textPaint);
																startx=startxWill;
															}else{
																starty+=lineHeight;
																startx=primex;
																startxWill=startx+advance;
																if(index>=selectionStart&&index<selectionEnd){//画选中高亮
																	canvas.drawRect(startx,starty,startxWill,starty+lineHeight,selectionbgcolor);
																}else if(index>=selectionEnd&&index<selectionStart){
																	canvas.drawRect(startx,starty,startxWill,starty+lineHeight,selectionbgcolor);
																}
																canvas.drawText(Character.toString(ch),startx,starty+baseline,textPaint);
																startx=startxWill;
															}
														}
													}else{
														break;
													}
												}
												break outmost;
											}else if(ch=='\n'){
												//textPaint.setColor(0xff00ff00);
												break;
											}else if(ch=='\t'){
												int xxwill=((xx-primex)/tablen+1)*tablen+primex;
												if(xxwill<vw){
													xx=xxwill;
												}else{
													break;
												}
											}else{
												int xxwill=xx+textWS[ii];
												if(xxwill<vw){
													xx=xxwill;
												}else{
													//textPaint.setColor(0xffff0000);
													break;
												}
											}
										}else{
											Paint p=new Paint();
											p.setStyle(Paint.Style.FILL);
											p.setColor(currentLineHighlight);
											canvas.drawRect(scrollX,starty,vw+scrollX,starty+lineHeight,p);
											break;
										}
									}
									for( ;true;index++){//画出一行文本
										if(index==selectionStart){//画光标
											if(index==selectionEnd){
												measureHandle(startx,starty);
												if(showCursor){
													canvas.drawLine(startx,starty,startx,starty+lineHeight,cursor);
												}
											}else{
												measureHandleStart(startx,starty);
											}
										}else if(index==selectionEnd){
											if(selectionStart!=selectionEnd){
												measureHandleEnd(startx,starty);
											}
										}
										int scrollYMaximum_will=starty+lineHeight;
										scrollYMaximum=scrollYMaximum_will>scrollYMaximum?scrollYMaximum_will:scrollYMaximum;
										if(starty-scrollY>vh){
											break outloop;
										}
										if(index<text.length){
											char ch=text[index];
											if(ch=='\n'){
												int startyWill=starty+lineHeight;
												int startxWill=primex;
												if(index>=selectionStart&&index<selectionEnd){//换行符是被选中的，画出它的背景高亮
													canvas.drawRect(startx,starty,vw+scrollX,starty+lineHeight,selectionbgcolor);
												}else if(index>=selectionEnd&&index<selectionStart){
													canvas.drawRect(startx,starty,vw+scrollX,starty+lineHeight,selectionbgcolor);
												}
												startx=startxWill;
												starty=startyWill;
												break;
											}else if(ch=='\t'){
												int startxWill=((startx-primex)/tablen+1)*tablen+primex;
												if(index>=selectionStart&&index<selectionEnd){//画选中高亮
													canvas.drawRect(startx,starty,startxWill,starty+lineHeight,selectionbgcolor);
												}else if(index>=selectionEnd&&index<selectionStart){
													canvas.drawRect(startx,starty,startxWill,starty+lineHeight,selectionbgcolor);
												}
												if(startxWill<vw){
													startx=startxWill;
												}else{
													starty+=lineHeight;
													startx=primex;
													break;
												}
											}else{
												int advance=textWS[index];
												int startxWill=startx+advance;
												if(startxWill<vw){
													if(index>=selectionStart&&index<selectionEnd){//画选中高亮
														canvas.drawRect(startx,starty,startxWill,starty+lineHeight,selectionbgcolor);
													}else if(index>=selectionEnd&&index<selectionStart){
														canvas.drawRect(startx,starty,startxWill,starty+lineHeight,selectionbgcolor);
													}
													canvas.drawText(Character.toString(ch),startx,starty+baseline,textPaint);
													//textPaint.setColor(textColor);
													startx=startxWill;
												}else{
													starty+=lineHeight;
													startx=primex;
													//textPaint.setColor(0xffff0000);
													index--;
													break;
												}
											}
											//textPaint.setColor(textColor);
										}else{
											break outloop;
										}
									}
								}else{
									Paint p=new Paint();
									p.setStyle(Paint.Style.FILL);
									p.setColor(currentLineHighlight);
									canvas.drawRect(scrollX,starty,vw+scrollX,starty+lineHeight,p);
									if(index==selectionStart){//画光标
										if(index==selectionEnd){
											measureHandle(startx,starty);
											if(showCursor){
												canvas.drawLine(startx,starty,startx,starty+lineHeight,cursor);
											}
										}else{
											measureHandleStart(startx,starty);
										}
									}else if(index==selectionEnd){
										if(selectionStart!=selectionEnd){
											measureHandleEnd(startx,starty);
										}
									}
									break;
								}
							}
							break;
						}
					}else{
						break;
					}
				}
			}
			if(handleOnShow){
				if(selectionStart==selectionEnd){
					if(handlePath1!=null)
						canvas.drawPath(handlePath1,handle);
				}else{
					if(handlePath1!=null)
						canvas.drawPath(handlePath1,handle);
					if(handlePath2!=null)
						canvas.drawPath(handlePath2,handle);
				}
			}
		}else{
			int textColorSaved=textPaint.getColor();
			textPaint.setColor(0xff777777);
			canvas.drawText("Null",getPaddingLeft(),getPaddingTop()+lineHeight,textPaint);
			textPaint.setColor(textColorSaved);
		}
	}
    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if(!canEdit)return true;
        super.dispatchKeyEvent(event);
        if(event.getAction()==KeyEvent.ACTION_DOWN){
            int keycode=event.getKeyCode();
            switch(keycode){
                case KeyEvent.KEYCODE_DPAD_LEFT:
                    if(ma.gui.batch.getVisibility()==VISIBLE){
                        moveSelection(0,-1);
                        showCursor=true;
                        tcv.againWait=true;
                        tcv.interrupt();
                        invalidate();
                    }else if(selectionStart==selectionEnd){
                        moveSelection(-1,-1);
                        invalidate();
                    }
                    break;
                case KeyEvent.KEYCODE_DPAD_RIGHT:
                    if(ma.gui.batch.getVisibility()==VISIBLE){
                        moveSelection(0,1);
                        invalidate();
                    }else if(selectionStart==selectionEnd){
                        moveSelection(1,1);
                        showCursor=true;
                        tcv.againWait=true;
                        tcv.interrupt();
                        invalidate();
                    }
                    break;
                case KeyEvent.KEYCODE_DPAD_UP:
                    break;
                case KeyEvent.KEYCODE_DPAD_DOWN:
                    break;
                case KeyEvent.KEYCODE_DEL:
                    boolean modif=false;
                    if(selectionStart==selectionEnd){
                        if(selectionStart>0){
                            modif=true;
                            repl(selectionStart-1,selectionStart,null);
                            showCursor=true;
                            tcv.againWait=true;
                            tcv.interrupt();
                            letSelection(selectionStart-1);
                            invalidate();
                        }
                    }else{
                        modif=true;
                        int a=Math.min(selectionStart,selectionEnd);
                        int b=Math.max(selectionStart,selectionEnd);
                        repl(a,b,null);
                        letSelection(a);
                        invalidate();
                    }
                    int titleIndex=ma.gui.titleIndex;
                    if(ma.gui.getChildAt(titleIndex)==ma.gui.batch){
                        ma.gui.removeViewAt(titleIndex);
                        ma.gui.addView(ma.gui.titlebar,titleIndex);
                    }
                    if(modif){
                        atTextChanged();
                    }
                    break;
            }
        }
        return true;
    }
	@Override
	public InputConnection onCreateInputConnection(EditorInfo outAttrs){
        InputConnection former=super.onCreateInputConnection(outAttrs);
		MyInputConnection ic=new MyInputConnection(this);
		mic=ic;
        mic.former=former;
		return ic;//super.onCreateInputConnection(outAttrs);
	}
    public class MyInputConnection extends BaseInputConnection{
        IndentEditor ie;
        InputConnection former;
        MainActivity ma;
        MyInputConnection(IndentEditor ie){
            super(ie,false);
            this.ie=ie;
            ma=ie.ma;
            
        }

        @Override
        public boolean requestCursorUpdates(int cursorUpdateMode) {
            return super.requestCursorUpdates(cursorUpdateMode);
        }

        @Override
        public boolean commitText(CharSequence text, int newCursorPosition, TextAttribute textAttribute) {
            return false;
        }

        @Override
        public boolean commitText(CharSequence txt,int newCursorPosition){
            if(!canEdit)return true;
            String text=txt.toString();
            boolean modified=false;
            if(selectionStart!=selectionEnd){
                modified=true;
            }else if(text.length()>0){
                modified=true;
            }
            if(!modified)return true;
            if(ma.gui.ebi.num){
                text=text.replace('1','①');
                text=text.replace('2','②');
                text=text.replace('3','③');
                text=text.replace('4','④');
                text=text.replace('5','⑤');
                text=text.replace('6','⑥');
                text=text.replace('7','⑦');
                text=text.replace('8','⑧');
                text=text.replace('9','⑨');
            }
            if(ma.gui.ebi.capsLock){
                text=text.toUpperCase();
            }
            ie.repl(ie.selectionStart,ie.selectionEnd,text.toCharArray());
            ie.selectionStart=ie.selectionStart+text.length()-1+newCursorPosition;
            ie.selectionEnd=ie.selectionStart;/*
            if(text.equals("\n")){
                if(autoIndentOnEnterKey){
                    if(selectionStart==selectionEnd){
                        String insert="\n";
                        for(int index=selectionStart-1;true;index--){
                            if(index>=0){
                                char ch=text.charAt(index);
                                if(ch=='\n'){
                                    break;
                                }else if(ch=='\t'){
                                    insert=insert+'\t';
                                }else{
                                    insert="\n";
                                }
                            }else{break;}
                        }
                        //log.alert("23333");
                        repl(selectionEnd,selectionEnd,insert.toCharArray());
                        letSelection(selectionStart+insert.length());
                    }
                }else{
                    //log.alert("insert enter");
                    int a=selectionStart;
                    int b=selectionEnd;
                    replace(a,b,new char[]{'\n'});
                    letSelection(a);
                }
            }else{
                
            }*/
            atTextChanged();
            return true;
        }
        @Override
        public boolean deleteSurroundingText(int beforeLength,int afterLength){
            if(!canEdit)return true;
            int a,b;
            boolean modified=false;
            if(selectionStart==selectionEnd){
                a=Math.max(selectionStart-beforeLength,0);
                b=selectionStart;
                if(a!=b)modified=true;
                ie.repl(a,b,null);
                
                ie.showCursor=true;
                ie.tcv.againWait=true;
                ie.tcv.interrupt();
                b=Math.min(a+afterLength,length());
   
                repl(a,b,null);
                letSelection(a);
                ie.invalidate();
            }else{
                modified=true;
                a=Math.min(selectionStart,selectionEnd);
                b=Math.max(selectionStart,selectionEnd);
                repl(a,b,null);
                letSelection(a);
            } /*if(ie.selectionStart<ie.selectionEnd){
                a=ie.selectionStart-beforeLength;
                b=ie.selectionEnd+afterLength;
            }else{
                a=ie.selectionEnd-beforeLength;
                b=ie.selectionStart+afterLength;
            }*/
            if(modified){
                //log.alert("at delete surround");
                atTextChanged();
            }
            return true;
        }
        @Override
        public boolean sendKeyEvent(KeyEvent event){
            return former.sendKeyEvent(event);
        }
        @Override
        public boolean setSelection(int start,int end){
            return false;
        }
    }
    class InertiaScroll extends Thread{
        int orientation;
        double initialSpeed;
        double minSpeed=0.001;
        double inertia;
        int initialScrollX;
        int initialScrollY;
        InertiaScroll(){
            inertia=0.001;//(10*ma.dp)/1000;
        }
        @Override
        public void run(){
            super.run();
            long initialTime=System.currentTimeMillis();
            long dTime;
            if(orientation==0){
                int scrollXWill;
                int scrollXSaved=initialScrollX;
                if(initialSpeed<0){
                    //log.alert("<0");
                    try{
                        sleep(1);
                    }catch(Exception e){}
                    while(!interrupted()){
                        dTime=System.currentTimeMillis()-initialTime;
                        double speedNow=initialSpeed+inertia*dTime;
                        if(speedNow<-minSpeed){
                            //scrollXWill=initialScrollX-(int)(initialSpeed*dTime+inertia*dTime*dTime/2);
                            scrollXWill=initialScrollX-(int)((initialSpeed+(inertia*dTime)/2)*dTime);
                            if(scrollXWill>scrollXSaved){
                                post(new LetScroll(scrollXWill,initialScrollY));
                            }
                            scrollXSaved=scrollXWill;
                        }else{
                            break;
                        }
                    }
                }else if(initialSpeed>0){
                    try{
                        sleep(1);
                    }catch(Exception e){}
                    while(!interrupted()){
                        dTime=System.currentTimeMillis()-initialTime;
                        double speedNow=initialSpeed-inertia*dTime;
                        if(speedNow>minSpeed){
                            scrollXWill=initialScrollX-(int)(initialSpeed*dTime-inertia*dTime*dTime/2);
                            //scrollXWill=initialScrollX-(int)((initialSpeed-(inertia*dTime)/2)*dTime);
                            if(scrollXWill<scrollXSaved){
                                if(scrollXWill<=0){
                                    post(new LetScroll(0,initialScrollY));
                                    return;
                                }
                                post(new LetScroll(scrollXWill,initialScrollY));
                            }
                            scrollXSaved=scrollXWill;
                        }else{
                            break;
                        }
                    }
                }else{
                    return;
                }
            }else if(orientation==1){
                if(initialSpeed<0){
                    try{
                        sleep(1);
                    }catch(Exception e){}
                    int scrollYSaved=initialScrollY;
                    //log.alert("上滑");
                    while(!interrupted()){
                        dTime=System.currentTimeMillis()-initialTime;
                        double speedNow=initialSpeed+inertia*dTime;
                        if(speedNow<-minSpeed){
                            //int scrollYWill=initialScrollY-(int)(initialSpeed*dTime+inertia*dTime*dTime/2);
                            int scrollYWill=initialScrollY-(int)((initialSpeed+(inertia*dTime)/2)*dTime);
                            if(scrollYWill>scrollYSaved){
                                if(scrollYWill>=scrollYMaximum){
                                    post(new LetScroll(initialScrollX,scrollYMaximum));
                                    return;
                                }
                                post(new LetScroll(initialScrollX,scrollYWill));
                            }
                            scrollYSaved=scrollYWill;
                        }else{
                            break;
                        }
                    }
                }else if(initialSpeed>0){
                    try{
                        sleep(1);
                    }catch(Exception e){}
                    int scrollYSaved=initialScrollY;
                    while(!interrupted()){
                        dTime=System.currentTimeMillis()-initialTime;
                        double speedNow=initialSpeed-inertia*dTime;
                        if(speedNow>minSpeed){
                            int scrollYWill=initialScrollY-(int)((initialSpeed-(inertia*dTime)/2)*dTime);
                            if(scrollYWill<scrollYSaved){
                                if(scrollYWill<=0){
                                    post(new LetScroll(initialScrollX,0));
                                    return;
                                }
                                post(new LetScroll(initialScrollX,scrollYWill));
                            }
                            scrollYSaved=scrollYWill;
                        }else{
                            break;
                        }
                    }
                }else return;
            }else return;
        }
        class LetScroll implements Runnable{
            int x,y;
            LetScroll(int x,int y){
                this.x=x;
                this.y=y;
            }
            @Override
            public void run(){
                scrollX=x;
                scrollY=y;
                invalidate();
            }
        }
	}
	class WaitLongClick extends Thread{
		int interval=400;
		Point lastTouch=new Point();
		boolean waited=false;
		@Override
		public void run(){
			super.run();
			try{
				sleep(interval);
			}catch(Exception e){}
			if(waited){
				return;
			}else{
				waited=true;
			}
			//handle.setColor(0xffff0000);
			if(fingerPressed){
				if(!fingerMoved){
					if(touchCtrl==0){
						post(new Runnable(){
							@Override
							public void run(){
								handleOnShow=true;
								if(ahh!=null){
									ahh.interrupt();
								}
								if(selectionStart!=selectionEnd){
									ma.gui.removeViewAt(ma.gui.titleIndex);
                                    ma.gui.addView(ma.gui.batch,ma.gui.titleIndex,ma.gui.titlebarlp);
								}else{
                                    ma.gui.removeViewAt(ma.gui.titleIndex);
                                    ma.gui.addView(ma.gui.batch,ma.gui.titleIndex,ma.gui.titlebarlp);
									final int tablen=(int)textPaint.measureText(tabWidth);
									final int px=lastTouch.x+scrollX;
									final int py=lastTouch.y+scrollY;
									//计算手指按住的是哪个字符，并选中
									if(horizontalScrollable){
										for(int index=0,x=getPaddingRight(),y=getPaddingTop(),glyph=0;true;index++,glyph++){
											if(index<text.length){
												char ch=text[index];
												if(ch=='\\'){
													if(++index<text.length){
														ch=text[index];
														if(ch=='p'){
															if(++index<text.length){
																ch=text[index];
																int w=ch>>>8;
																int h=ch&0x00ff;
																int outWidth=w*lineHeight/h;
																int xwill=x+outWidth;
																if((index+=w*h)<text.length){
																	if(px>=x&&px<xwill&&py>=y&&py<y+lineHeight){
																		selectionStart=glyph;
																		selectionEnd=glyph+1;
																		invalidate();
																		break;
																	}
																	x=xwill;
																}else{
																	if(px>=x&&px<xwill&&py>=y&&py<y+lineHeight){
																		selectionStart=glyph;
																		selectionEnd=glyph+1;
																		invalidate();
																		break;
																	}else if(px>=xwill&&py>=y&&py<y+lineHeight){
																		selectionStart=glyph+1;
																		selectionEnd=glyph+1;
																		invalidate();
																	}
																	x=xwill;
																	break;
																}
															}else{
																break;
															}
														}else if(ch=='\\'){
															int advance=textWS[glyph];
															int xwill=x+advance;
															if(px>=x&&px<xwill&&py>=y&&py<y+lineHeight){
																selectionStart=glyph;
																selectionEnd=glyph+1;
																invalidate();
																break;
															}
															x=xwill;
														}else{
															index--;
															continue;
														}
													}else{
														int advance=textWS[glyph];
														int xwill=x+advance;
														if(px>=x&&px<xwill&&py>=y&&py<y+lineHeight){
															selectionStart=glyph;
															selectionEnd=glyph+1;
															invalidate();
														}else if(px>=xwill&&py>=y&&py<y+lineHeight){
															selectionStart=glyph+1;
															selectionEnd=glyph+1;
															invalidate();
														}
														break;
													}
												}else if(ch=='\t'){
													int xwill=((x-getPaddingLeft())/tablen+1)*tablen;
													if(px>=x&&px<xwill&&py>=y&&py<y+lineHeight){
														selectionStart=glyph;
														selectionEnd=glyph+1;
														invalidate();
														break;
													}
													x=xwill;
												}else if(ch=='\n'){
													int ywill=y+lineHeight;
													if(px>=x&&py>=y&&py<y+lineHeight){
														selectionStart=glyph;
														selectionEnd=glyph;
														break;
													}
													x=getPaddingLeft();
													y=ywill;
												}else{
													int advance=textWS[glyph];
													int xwill=x+advance;
													if(px>=x&&px<xwill&&py>=y&&py<y+lineHeight){
														selectionStart=glyph;
														selectionEnd=glyph+1;
														invalidate();
														break;
													}
													x=xwill;
												}
											}else{
												if(px>=x&&py>=y){
													selectionStart=glyph;
													selectionEnd=glyph;
													invalidate();
												}
												break;
											}
										}
									}else{//计算折行文本单击位置
										for(int index=0,x=getPaddingRight(),y=getPaddingTop(),glyph=0;true;index++,glyph++){
											if(index<text.length){
												char ch=text[index];
												if(ch=='\\'){
													if(++index<text.length){
														ch=text[index];
														if(ch=='p'){
															if(++index<text.length){
																ch=text[index];
																int w=ch>>>8;
																int h=ch&0x00ff;
																int outWidth=w*lineHeight/h;
																int xwill=x+outWidth;
																if((index+=w*h)<text.length){
																	if(xwill<getWidth()){
																		if(px>=x&&px<xwill&&py>=y&&py<y+lineHeight){
																			selectionStart=glyph;
																			selectionEnd=glyph+1;
																			invalidate();
																			break;
																		}
																		x=xwill;
																	}else{
																		if(px>=x&&py>=y&&py<y+lineHeight){
																			selectionStart=glyph;
																			selectionEnd=glyph;
																			invalidate();
																			break;
																		}
																		x=getPaddingLeft();
																		xwill=x+outWidth;
																		y+=lineHeight;
																		if(px<xwill&&py>=y&&y<y+lineHeight){
																			selectionStart=glyph;
																			selectionEnd=glyph;
																			invalidate();
																			break;
																		}
																	}
																}else if(xwill<getWidth()){
																	if(px>=x&&px<xwill&&py>=y&&py<y+lineHeight){
																		selectionStart=glyph;
																		selectionEnd=glyph+1;
																		invalidate();
																		break;
																	}else if(px>=xwill&&py>=y&&py<y+lineHeight){
																		selectionStart=glyph+1;
																		selectionEnd=glyph+1;
																		invalidate();
																	}
																	x=xwill;
																	break;
																}else{
																	if(px>=x&&py>=y&&py<y+lineHeight){
																		selectionStart=glyph;
																		selectionEnd=glyph;
																		invalidate();
																		break;
																	}
																	x=getPaddingLeft();
																	xwill=x+outWidth;
																	y+=lineHeight;
																	if(px<xwill&&py>=y&&y<y+lineHeight){
																		selectionStart=glyph;
																		selectionEnd=glyph+1;
																		invalidate();
																		break;
																	}
																	break;
																}
															}else{
																break;
															}
														}else if(ch=='\\'){
															int advance=textWS[glyph];
															int xwill=x+advance;
															if(px>=x&&px<xwill&&py>=y&&py<y+lineHeight){
																selectionStart=glyph;
																selectionEnd=glyph+1;
																invalidate();
																break;
															}
															x=xwill;
														}else{
															index--;
															continue;
														}
													}else{
														int advance=textWS[glyph];
														int xwill=x+advance;
														if(px>=x&&px<xwill&&py>=y&&py<y+lineHeight){
															selectionStart=glyph;
															selectionEnd=glyph+1;
															invalidate();
														}else if(px>=xwill&&py>=y&&py<y+lineHeight){
															selectionStart=glyph+1;
															selectionEnd=glyph+1;
															invalidate();
														}
														break;
													}
												}else if(ch=='\t'){
													int xwill=((x-getPaddingLeft())/tablen+1)*tablen;
													if(xwill<getWidth()){
														if(px>=x&&px<xwill&&py>=y&&py<y+lineHeight){
															selectionStart=glyph;
															selectionEnd=glyph+1;
															invalidate();
															break;
														}
														x=xwill;
													}else{
														if(px>=x&&py>=y&&py<y+lineHeight){
															selectionStart=glyph;
															selectionEnd=glyph;
															invalidate();
															break;
														}
														x=getPaddingLeft();
														y+=lineHeight;
													}
												}else if(ch=='\n'){
													int ywill=y+lineHeight;
													if(px>=x&&py>=y&&py<y+lineHeight){
														selectionStart=glyph;
														selectionEnd=glyph;
														invalidate();
														break;
													}
													x=getPaddingLeft();
													y=ywill;
												}else{
													int advance=textWS[glyph];
													int xwill=x+advance;
													if(xwill<getWidth()){
														if(px>=x&&px<xwill&&py>=y&&py<y+lineHeight){
															selectionStart=glyph;
															selectionEnd=glyph+1;
															invalidate();
															break;
														}
														x=xwill;
													}else{
														if(px>=x&&py>=y&&py<y+lineHeight){
															selectionStart=glyph;
															selectionEnd=glyph;
															invalidate();
															break;
														}
														x=getPaddingLeft();
														y+=lineHeight;
														xwill=x+advance;
														if(px>=x&&px<xwill&&py>=y&&py<y+lineHeight){
															selectionStart=glyph;
															selectionEnd=glyph+1;
															invalidate();
															break;
														}
														x=xwill;
													}
												}
											}else{
												if(px>=x&&py>=y){
													selectionStart=glyph;
													selectionEnd=glyph;
													invalidate();
												}
												break;
											}
										}
									}
								}
							}
						});
					}else if(touchCtrl==1){
						//log.alert("ctrl=1");
						post(new Runnable(){
							public void run(){
								ma.gui.removeViewAt(ma.gui.titleIndex);
                                ma.gui.addView(ma.gui.batch,ma.gui.titleIndex,ma.gui.titlebarlp);
							}
						});
					}
				}
			}
		}
	}
    class AutoHideHandle extends Thread{
        @Override
        public void run(){
            try{
                sleep(800);
                handleOnShow=false;
                IndentEditor.this.postInvalidate();
            }catch(InterruptedException e){
            }catch(Exception e){
                log.alert(e.toString());
            }
            super.run();
        }
	}
}
